package com.markyao.service;

import com.markyao.service.redis.RedisKeys;
import com.markyao.vo.PageParams;
import com.markyao.vo.RegistryBean;
import com.markyao.vo.pojo.AppBean;
import com.markyao.vo.pojo.ServiceBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j(topic = "m.RedisService")
@Service
public class RedisService {
    @Autowired
    StringRedisTemplate redisTemplate;

    private final List<AppBean> appbeanBuffers =new ArrayList<>(256);
    private final List<ServiceBean> servicesBuffers =new ArrayList<>(256);
    private final ExecutorService executors=Executors.newSingleThreadExecutor(new CustomizableThreadFactory("REFRESH-BUFFER-WORKER"));
    private final static String aliveValue="ALIVE";
    private final static String deadValue="DEAD";


    /**
     * 定时刷新缓存.
     */
    @PostConstruct
    private void refreshBuffers(){
       executors.submit(()->{
           while (true){
               appbeanBuffers.clear();
               Set<String> registryKeys = redisTemplate.keys(RedisKeys.SERVER_REGISTRY_KEY+"*");
               log.info("发现已注册主机数量 =>  {}", registryKeys.size());
               for (String registryKey : registryKeys) {
                   Map<Object, Object> entries = redisTemplate.opsForHash().entries(registryKey);
                   String appName = entries.get(RedisKeys.APPNAME).toString();
                   String url = entries.get(RedisKeys.URL).toString();
                   String weight = entries.get(RedisKeys.WEIGHT).toString();
                   String alive=buildAlive(appName,url);
                   AppBean appBean=new AppBean();
                   appBean.setAppName(appName);
                   appBean.setUrl(url);
                   appBean.setWeight(weight);
                   appBean.setAlive(alive);
                   appbeanBuffers.add(appBean);
               }
               servicesBuffers.clear();
               Set<String> providersKeys = redisTemplate.keys(RedisKeys.PROVIDERS_KEY + "*");
               for (String providersKey : providersKeys) {
                   String interfaceName = providersKey.substring(RedisKeys.PROVIDERS_KEY.length());
                   Map<Object, Object> entries = redisTemplate.opsForHash().entries(providersKey);
                   for (Map.Entry<Object, Object> e : entries.entrySet()) {
                       String url = e.getKey().toString();
                       String appName = redisTemplate.opsForValue().get(RedisKeys.URL_MAP_KEY+url).toString();
                       ServiceBean serviceBean=new ServiceBean();
                       serviceBean.setProviderName(appName);
                       serviceBean.setInterfaceName(interfaceName);
                       String instance = redisTemplate.opsForHash()
                               .get(RedisKeys.SERVICE_REGISTRY_KEY + appName, interfaceName).toString();
                       serviceBean.setInstanceName(instance);
                       serviceBean.setDetails("...");
                       servicesBuffers.add(serviceBean);
                   }

               }
               log.info("【刷新注册中心缓存完毕】");
               Thread.sleep(15 * 1000);
           }
       });
    }
    private String buildAlive(String appName,String url){
        Boolean hasKey = redisTemplate.hasKey(RedisKeys.buildHeartBeatKey(appName, url));
        String alive=hasKey ? aliveValue : deadValue;
        return alive;
    }

    public List<AppBean>getList(PageParams pageParams){
        Integer currentPage = pageParams.getCurrentPage();
        Integer pageSize = pageParams.getPageSize();
        if (null == appbeanBuffers || appbeanBuffers.size() ==0 || null == currentPage || currentPage<=0)
            return Collections.emptyList();
        pageParams.setTotal((long) appbeanBuffers.size());
        int toIndex = currentPage + pageSize -1;
        if (toIndex>= appbeanBuffers.size())
            toIndex= appbeanBuffers.size();
        return appbeanBuffers.subList(currentPage - 1, toIndex);
    }

    public RegistryBean getRegistryBean(String appName) {
        Map<Object, Object> basicMp = redisTemplate.opsForHash().entries(RedisKeys.SERVER_REGISTRY_KEY + appName);

        RegistryBean registryBean=new RegistryBean();

        Object o1 = basicMp.get(RedisKeys.APPNAME);
        Object o2 = basicMp.get(RedisKeys.URL);
        Object o3 = basicMp.get(RedisKeys.WEIGHT);
        AppBean appBean=new AppBean();
        appBean.setAppName(o1.toString());
        appBean.setUrl(o2.toString());
        appBean.setWeight(o3.toString());
        appBean.setAlive(buildAlive(appName, o2.toString()));

        registryBean.setAppBean(appBean);

        Boolean isProvider = redisTemplate.hasKey(RedisKeys.SERVER_REGISTRY_KEY + appName);
        if (!isProvider)
            registryBean.setRegistedServices(Collections.emptyList());
        else {
            List<String> registedServices = new ArrayList<>(16);
            Map<Object, Object> entries = redisTemplate.opsForHash().entries(RedisKeys.SERVICE_REGISTRY_KEY + appName);
            for (Object k : entries.keySet()) {
                String m=k.toString()+":: 实现 ==> "+entries.get(k).toString();
                registedServices.add(m);
            }
            registryBean.setRegistedServices(registedServices);
        }

        Boolean isRefrence = redisTemplate.hasKey(RedisKeys.REFRENCE_REGISTRY_KEY + appName);
        if (!isRefrence){
            registryBean.setNeedingsServices(Collections.emptyList());
        }else {
            Set<String> refrences = redisTemplate.opsForSet().members(RedisKeys.REFRENCE_REGISTRY_KEY + appName);
            registryBean.setNeedingsServices(new ArrayList<>(refrences));
        }

        return registryBean;
    }

    public List<ServiceBean> getServices(PageParams pageParams) {
        Integer currentPage = pageParams.getCurrentPage();
        Integer pageSize = pageParams.getPageSize();
        if (null == servicesBuffers || servicesBuffers.size() ==0 || null == currentPage || currentPage<=0)
            return Collections.emptyList();
        pageParams.setTotal((long) servicesBuffers.size());
        int toIndex = currentPage + pageSize -1;
        if (toIndex>= servicesBuffers.size())
            toIndex= servicesBuffers.size();
        return servicesBuffers.subList(currentPage - 1, toIndex);
    }
}
